package top.atcra.rpc.demo.globalTest;

import lombok.extern.slf4j.Slf4j;
import top.atcra.rpc.RPCBootstrap;
import top.atcra.rpc.demo.DemoApi;
import top.atcra.rpc.service.ReferenceConfig;
import top.atcra.rpc.transport.utils.RequestIdGenerator;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 客户端Demo，并行调用
 *
 * @author atcra
 * @date 2025-04-01
 */
@Slf4j
public class ParallelClientMain {

    static volatile long start;

    public static void main(String[] args) {
        log.info("客户端启动");

        int THREAD_NUM = 10, CALL_PER_THREAD = Integer.MAX_VALUE;
        int totalCount = THREAD_NUM * CALL_PER_THREAD;

        AtomicInteger errorCount = new AtomicInteger(0);
        CountDownLatch countDownLatch = new CountDownLatch(THREAD_NUM);
        try (ExecutorService pool = Executors.newFixedThreadPool(THREAD_NUM)) {
            for (int i = 0; i < THREAD_NUM; i++) {
                int finalI = i;
                pool.execute(() -> {
                    var client = new RPCBootstrap(RPCBootstrap.Role.CLIENT);
                    try {
                        var field = RPCBootstrap.class.getDeclaredField("requestIdGenerator");
                        field.setAccessible(true);
                        field.set(client, new RequestIdGenerator(0,finalI));
                    } catch (NoSuchFieldException | IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                    var reference = new ReferenceConfig<>("demoService",
                            "demo" + finalI, DemoApi.class);
                    client.reference(reference);
                    var proxy = reference.getProxy();
                    countDownLatch.countDown();
                    try {
                        countDownLatch.await();
                        start = System.currentTimeMillis();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    for (int j = 0; j < CALL_PER_THREAD; j++) {
                        try {
                            proxy.sayHello("atcra");
                        } catch (Exception e) {
                            errorCount.incrementAndGet();
                        }
                    }
                    client.shutdown();
                });
            }
            pool.shutdown();
            System.out.println(pool.awaitTermination(123456, java.util.concurrent.TimeUnit.SECONDS));
            long end = System.currentTimeMillis();
            System.out.printf("QPS: %f,Error rate: %f. \n", (double) totalCount * 1000 / (end - start), (double) errorCount.get() / totalCount);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }


    }
}
